package com.joshua.spring.gateway.repo;

import com.joshua.spring.gateway.constant.RedisConstants;
import com.joshua.spring.gateway.entity.bo.RouteDefinitionGroup;
import com.joshua.spring.gateway.entity.dto.RouteDefinitionGroupOptDTO;
import com.joshua.spring.gateway.entity.dto.RouteDefinitionRefreshEvent;
import com.joshua.spring.util.JacksonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.event.EventListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.*;


/**
 * projectName dragon-cloud
 * package com.joshua.spring.gateway.repo
 * classname  RedisRouteDefinitionRespository
 * <p>
 * description 路由在redis中的缓存
 * </p>
 *
 * @author <a href="mailto:joshualwork@163.com">joshua_liu</a>
 * @date 2020/8/20 17:11
 */
@Slf4j
@Component
public class RedisRouteDefinitionRepository implements ApplicationEventPublisherAware {
    public final Map<String, RouteDefinitionGroup> ROUTE_DEFINITION_GROUP = Collections.synchronizedMap(new LinkedHashMap<>());

    @Autowired
    private RedisTemplate redisTemplate;

    private ApplicationEventPublisher eventPublisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        eventPublisher = applicationEventPublisher;
    }

    Map<String, RouteDefinition> pull() {
        HashMap<String, RouteDefinition> map = new HashMap<>(128);
        List<String> routeInfos = redisTemplate.opsForHash().values(RedisConstants.GatewayKey.ROUTE_INFO_KEY);
        routeInfos.forEach(e -> {
            try {
                RouteDefinitionGroup routeDefinitionGroup = JacksonUtils.json2pojo(e, RouteDefinitionGroup.class);
                ROUTE_DEFINITION_GROUP.put(routeDefinitionGroup.getRouteId(), routeDefinitionGroup);
                map.put(routeDefinitionGroup.getRouteId(), routeDefinitionGroup.getRouteDefinition());
            } catch (Exception ex) {
                log.error("route definition json format element->[{}] fail", e, ex);
            }
        });
        return map;
    }

    /**
     * description: 推送信息到 {@link CachedRouteDefinitionRepository}
     * 重新从redis拉取路由信息
     *
     * @author <a href="mailto:joshualwork@163.com">joshua_liu</a>
     * @date 2020/8/22 16:28
     */
    public void reloadRouteDefinition() {
        eventPublisher.publishEvent(new RouteDefinitionRefreshEvent());
    }


    @EventListener
    public void routeChangeEventListener(RouteDefinitionGroupOptDTO dto) throws Exception {
        RouteDefinitionGroup routeDefinitionGroup = dto.getRouteDefinitionGroup();
        String key = RedisConstants.GatewayKey.ROUTE_INFO_KEY;
        String hashKey = String.format(RedisConstants.Formatter.KEY_FORMATTER, routeDefinitionGroup.getApplicationCode(),
                routeDefinitionGroup.getRouteId());
        String json = JacksonUtils.obj2json(routeDefinitionGroup);
        switch (dto.getOptType()) {
            case I:
            case U:
                redisTemplate.opsForHash().delete(key, hashKey);
                redisTemplate.opsForHash().put(key, hashKey, json);
                break;
            case D:
                redisTemplate.opsForHash().delete(key, hashKey);
            case R:
            default:
        }
        reloadRouteDefinition();
    }


}
